package main

import (
	"fmt"
	"strconv"
	"strings"

	"gitee.com/chenhonghua/common-service/cmd/exercise_repository/entity"
	"gitee.com/chenhonghua/common-service/cmd/segment/client"
	"gitee.com/chenhonghua/ginorigin/database"
	connsqlite "gitee.com/chenhonghua/ginorigin/database/connect/sqlite"
	"gitee.com/chenhonghua/ginorigin/env"
	"gitee.com/chenhonghua/ginorigin/http/restful"
	"gitee.com/chenhonghua/ginorigin/http/router"
	"gitee.com/chenhonghua/ginorigin/log"
	"github.com/gin-gonic/gin"
)

var (
	exercises []entity.Exercise
)

func init() {
	// 日志等级设置
	log.SetLogLevel(env.StringVal("LOG_LEVEL", "info"))

	// 数据库初始化
	database.DatabaseConfig{
		Enable:  true,
		LogMode: env.StringVal("SQL_LOG_LEVEL", "error"),
		DBConfig: &connsqlite.Sqlite{
			Path:         env.StringVal("SQLITE_HOST", "exercise_repository.db"),
			MaxIdleConns: env.IntVal("SQLITE_MAX_IDLE_CONN", 5),
			MaxOpenConns: env.IntVal("SQLITE_MAX_OPEN_CONN", 10),
		},
	}.Load()
	entity.Migrate() // migrate

	// 路由初始化
	router.RouterConfig{
		Enable:    true,
		LogEnable: true,
		AllowCors: true,
	}.Load()
	router.SetWriter(log.DefaultLogger.Out)
	restful.RegisterErrorFromCodeAndMessage(10001, "查询错误：关键词不能为空")
	restful.RegisterErrorFromCodeAndMessage(10002, "查询错误：错误的页码，页码必须大于0")
	restful.RegisterErrorFromCodeAndMessage(10003, "查询错误：错误的分页尺寸，分页尺寸必须大于0且小于100")
	restful.RegisterErrorFromCodeAndMessage(10101, "查询错误：参数错误")
	restful.RegisterErrorFromCodeAndMessage(10102, "查询错误：未找到指定题目")

	// 数据初始化
	if exercises, _ = entity.FindAll(); len(exercises) == 0 {
		exercises = make([]entity.Exercise, 0)
	}
}

func main() {
	// 路由注册
	v1Group := router.GetRouter().Group("/api/v1")
	v1Group.GET("health", restful.Success)                                                               // 健康检测
	v1Group.GET("state", func(ctx *gin.Context) { restful.Data(ctx, entity.StateDictionary) })           // 状态字典
	v1Group.GET("morphology", func(ctx *gin.Context) { restful.Data(ctx, entity.MorphologyDictionary) }) // 题型字典
	v1Group.GET("page", HANDLER_PAGE)                                                                    // 分页查询题目
	v1Group.GET(":id", HANDLER_GET)                                                                      // 查询指定题目

	// 启动服务
	if e := router.GetRouter().Run(fmt.Sprintf("0.0.0.0:%d", env.IntVal("SERVER_PORT", 58783))); e != nil {
		log.Fatal(e)
	}
}

type queryParam struct {
	kws        []string
	Page       int `json:"page"`
	Size       int `json:"size"`
	Total      int `json:"total"`
	startIndex int
	endIndex   int
	Data       []entity.Exercise `json:"data"`
}

func (qp *queryParam) setTotal(total int) {
	qp.Total = total
	if qp.startIndex >= qp.Total {
		qp.Page = qp.Total / qp.Size
		qp.startIndex = (qp.Page - 1) * qp.Size
		qp.endIndex = qp.Page * qp.Size
	}
	if qp.endIndex > qp.Total {
		qp.endIndex = qp.Total
	}
}

func (qp queryParam) match(exec entity.Exercise) bool {
	for _, kw := range qp.kws {
		if strings.Contains(exec.Content, kw) {
			return true
		} else if len(exec.Options) > 0 {
			isMatch := false
			for _, option := range exec.Options {
				if isMatch = strings.Contains(option.Content, kw); isMatch {
					return true
				}
			}
			if isMatch {
				return true
			}
		}
	}
	return false
}

func NewQueryParam(ctx *gin.Context) (*queryParam, *restful.E) {
	qp := queryParam{}

	page, e := strconv.Atoi(strings.TrimSpace(ctx.Query("page")))
	if e != nil || page <= 0 {
		page = 1
	}
	size, e := strconv.Atoi(strings.TrimSpace(ctx.Query("size")))
	if e != nil || size <= 0 || size > 100 {
		size = 10
	}
	qp.Page = page
	qp.Size = size
	qp.startIndex = (page - 1) * size
	qp.endIndex = page * size

	kw := strings.TrimSpace(ctx.Query("kw"))
	if len(kw) == 0 {
		qp.kws = []string{}
	} else {
		texts, e := client.Do(kw, true) // 分词
		if e != nil {
			qp.kws = []string{kw}
		} else {
			for _, text := range texts {
				qp.kws = append(qp.kws, text.Text)
			}
		}
	}

	return &qp, nil
}

// 查询题目
//
// 请求参数:
//
//	kw: 关键词
//	subject: 科目
//	page: 页码
//	size: 每页条数
var HANDLER_PAGE gin.HandlerFunc = func(ctx *gin.Context) {
	qp, err := NewQueryParam(ctx)
	if err != nil {
		err.Restful(ctx)
		return
	} else if len(qp.kws) == 0 {
		qp.setTotal(len(exercises))
		qp.Data = exercises[qp.startIndex:qp.endIndex]
		restful.Data(ctx, qp)
		return
	}
	var matchs []entity.Exercise = make([]entity.Exercise, 0)
	for _, exec := range exercises {
		if qp.match(exec) {
			matchs = append(matchs, exec)
		}
	}
	qp.setTotal(len(matchs))
	log.Infof("qp[%d][%d:%d]: %#v", len(exercises), qp.startIndex, qp.endIndex, qp)
	qp.Data = matchs[qp.startIndex:qp.endIndex]
	restful.Data(ctx, qp)
}

var HANDLER_GET gin.HandlerFunc = func(ctx *gin.Context) {
	id, e := strconv.Atoi(ctx.Param("id"))
	if e != nil {
		restful.Errors.FromCode(10101)
		return
	}
	for _, exer := range exercises {
		if exer.Id == id {
			restful.Data(ctx, exer)
			return
		}
	}
	restful.Errors.FromCode(10102)
}
